Skip to content

cython: add build-cython.yml for riscv64 wheels - #330

Open
luhenry wants to merge 5 commits into
mainfrom
cython
Open

cython: add build-cython.yml for riscv64 wheels#330
luhenry wants to merge 5 commits into
mainfrom
cython

Conversation

@luhenry

@luhenry luhenry commented Aug 24, 2026

Copy link
Copy Markdown
Member

Self-hosting: setup.py compiles Cython's own modules with the in-tree Cython. Upstream ships per-interpreter wheels plus a py3-none-any fallback, but nothing for riscv64.

Mirrors the build_wheels job in upstream's wheels.yml.

Matrix: cp312, cp313, cp314. No cp314t: setup.py disables self-compilation under Py_GIL_DISABLED, so a free-threaded build would silently ship the pure-Python fallback.

Testing

  • upstream's own runtests.py (C and C++ backends), staging runtests.py tests Demos docs cython.py cythonize.py. Cython/ is deliberately not staged, so the installed wheel is imported rather than the source tree.
  • -x embedded -x embed_modules — both link -lpython3.X, and manylinux CPython is static-only with no shared libpython. Not riscv64-specific.

License: ✅

Patches

  • 0001-Add-riscv64-cibuildwheel-environment-override.patch — To upstream [upstream has no riscv64 override]. [tool.cibuildwheel.linux.environment] sets -march=core2, which the riscv64 compiler rejects; without it the C compile fails immediately. riscv64-only.

@luhenry luhenry linked an issue Aug 24, 2026 that may be closed by this pull request
@threexc

threexc commented Aug 24, 2026

Copy link
Copy Markdown
Collaborator

The error is coming from upstream's pyproject.toml, starting at line 31:

[tool.cibuildwheel.linux.environment]
CFLAGS = "-O3 -g0 -pipe -fPIC -DNDEBUG -march=core2 -mno-ssse3"
AR = "gcc-ar"
NM = "gcc-nm"
RANLIB = "gcc-ranlib"
PIP_BUILD_CONSTRAINT = ".github/wheel_build_constraints.txt"
PIP_CONSTRAINT = ".github/wheel_build_constraints.txt"

There are sections following it for different architectures, e.g.:

[[tool.cibuildwheel.overrides]]
select = "*aarch64"
inherit.environment = "append"
environment = {CFLAGS = "-O3 -g0 -pipe -fPIC -DNDEBUG -march=armv8-a -mtune=cortex-a72", AR = "gcc-ar", NM = "gcc-nm", RANLIB = "gcc-ranlib"}

Easiest is to add a patch for our needs, and I can take this as a task to try getting upstream.

EDIT: I went to see how we build it for qemuriscv64 in Yocto (which also builds riscv64gc packages right now). Here's what I think is the key set of flags:

-march=rv64imafdc_zicsr_zifencei -mabi=lp64d -fstack-protector-strong

@threexc

threexc commented Aug 25, 2026

Copy link
Copy Markdown
Collaborator

@luhenry my bad, my suggestion to rework the triggers broke our UI experience a bit (not actually seeing the workflows running anymore). I'm going to get a revert in and improve the logic. Here is the workflow you triggered: https://github.com/riseproject-dev/python-wheels/actions/runs/32887623280

luhenry and others added 2 commits August 25, 2026 16:28
Cython ships per-interpreter compiled wheels (cp39-cp315) plus a
py3-none-any fallback on PyPI, but none for riscv64 -- which every
source build of a Cython-using package on riscv64 needs (protobuf,
fonttools, grpcio-tools, etc. all compile Cython from sdist today).

Cython is self-hosting: setup.py compiles its own modules with the
in-tree Cython, so the build-from-checkout shape needs no external
build tool. Matrix is per-interpreter [cp312, cp313, cp314] with no
cp314t -- setup.py disables self-compilation under Py_GIL_DISABLED, so
a free-threaded build would silently ship the pure-Python fallback.

The wheel test asserts a core module loaded from a compiled .so (a
self-compile failure degrades to the pure-Python fallback silently)
and then cythonizes+compiles+imports a module to prove the wheel works
as a compiler end-to-end.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
The CI build failed because upstream's pyproject.toml [tool.cibuildwheel]
config sets x86 CFLAGS (-march=core2 -mno-ssse3) with per-arch overrides
for aarch64/armv7l but none for riscv64, so the riscv64 build inherited
the x86 flags and gcc rejected them ("ISA string must begin with rv").

Add patches/cython/3.3.0/ with a riscv64 [tool.cibuildwheel] override
(applied matplotlib/pillow-style via a second checkout + git apply),
using the RVA-baseline flags used for riscv64gc builds. Also add
patches/cython/** to the PR paths trigger.

Replace the placeholder smoke test with upstream's own suite
(Tools/ci-run.sh): runtests.py over the bundled tests/, C and C++
backends. runtests.py + tests/ are copied into cibuildwheel's temp test
cwd (not the source Cython/) so the suite exercises the installed wheel,
not the checkout's pure-Python source.

Validated end-to-end under QEMU: cp312 wheel builds with 19 compiled
.so, and a runtests.py shard passes 186 tests against it.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
EmbedTest chdirs to Demos/embed and the end-to-end srctrees compile fixtures
from docs/ and invoke the root cython.py / cythonize.py, none of which were
staged, so all three interpreters failed in runtests.py after building
cleanly. Cython/ stays unstaged, so cython.py still resolves the compiler
from the installed wheel.
EmbedTest and the embed_modules end-to-end case both link -lpython3.X, and
the manylinux CPython is static-only with no shared libpython, so ld fails
with "cannot find -lpython3.12". Not riscv64-specific: upstream runs these
on runners that have a shared libpython. runtests.py gates EmbedTest on an
exclude selector matching "embedded" (runtests.py:814); the srctree case
matches its module name.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

cython riscv64 support

2 participants